题目:面试题中经常会遇到,给定一个0,1矩阵,0表示可走,1表示不可走。求出从左上角到右下角的最短路径?
例如:矩阵A={
{0,0,1,0},
{1,0,1,0},
{0,0,1,0},
{0,0,0,0}
};
这里我们就可以用广度优先算法来实现:
import java.util.LinkedList;
public class MiGong {
public static void main(String[] args) {
int[][] array={
{0,0,1,0},
{1,0,1,0},
{0,0,1,0},
{0,0,0,0}
};
new MiGong().findMinRold(array);
}
//定义图的节点信息
class Node{
//定义坐标和距离第一个节点的距离
int x;
int y;
int dis;
//定义节点的前缀,用于绘制整个最短路径的 线路图
Node pre;
public Node(int x , int y , int dis , Node pre) {
this.x = x;
this.y = y;
this.dis = dis;
this.pre = pre;
}
}
public void findMinRold(int[][] arr) {
//定义 上下左右四个方向
int[][] direction = {{1,0},{-1,0},{0,1},{0,-1}};
//创建队列
LinkedList<Node> queue = new LinkedList<Node>();
//创建开始节点
Node start = new Node(0,0,0,null);
//把开始节点放入队列中,并做下标记,在原来数组中做标记
queue.offer(start);
arr[0][0] = 1;
//循环操作队列,进行广度遍历
Node temp = null;
ok:
while(!queue.isEmpty()) {
temp = queue.poll();
//依次遍历这个节点的四个方向,查找还没有遍历的相连节点
for(int i = 0 ; i < 4 ; i++) {
int newX = temp.x + direction[i][0];
int newY = temp.y + direction[i][1];
//是否越界,坐标
if(newX < 0 || newX >= 4 || newY < 0 || newY >= 4) {
continue;
}
//判断是否该节点可以通过,即为0
if(arr[newX][newY] == 1) {
continue;
}
//构造节点
Node next = new Node(newX , newY , temp.dis+1 , temp);
//该节点可以通过,判断该节点是否是最终节点
if(newX == 3 && newY == 3) {
queue.clear();
//相当于头插法,转置
queue.offerFirst(next);
Node preNode = next.pre;
while(preNode != null) {
queue.offerFirst(preNode);
preNode = preNode.pre;
}
int len = queue.size();
System.out.println("最短路径长度为:"+(len-1));
for(Node it:queue) {
System.out.println("("+it.x+","+it.y+") ");
}
break ok;
}
arr[newX][newY] = 1;
queue.offer(next);
}//for
}//while
}
}
附录:BFS求解第一个节点到其他节点之间的最短路径问题:
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeMap;
public class BFS {
public static void main(String[] args) {
int[][] arr = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
int[][] mark = new int[4][4];
new BFS().BFS(arr, mark);
}
//构造节点,包括x和y、以及与第一个节点的距离
class Node{
int x;
int y;
int dis;
public Node(int x , int y , int dis) {
this.x = x ;
this.y = y ;
this.dis = dis ;
}
}
// 1:使用队列LinkedList 2:使用标记数组mark和坐标
public void BFS(int[][] arr , int[][] mark) {
//记录每个节点到第一个节点的最短距离
Map<Integer,Integer> map = new TreeMap<Integer,Integer>();
//上下左右四个方向
int[][] derect = {{1,0},{-1,0},{0,1},{0,-1}};
//建立一个队列
LinkedList<Node> queue = new LinkedList<Node>();
//初始化第一个节点
Node start = new Node(0,0,0);
//把第一个节点放到队列中去
queue.offer(start);
//置该点标记为为1,表示已经访问过
mark[0][0] = 1;
//第一个节点到自己的距离
map.put(1, 0);
while(!queue.isEmpty()) {
//出队列
Node temp = queue.poll();
//将其相关联的节点找出来,并依次进入队列
for(int i = 0 ; i < 4 ; i++) {
//寻找相连节点
int newX = temp.x + derect[i][0];
int newY = temp.y + derect[i][1];
//新的坐标越界了,继续下一次循环
if(newX < 0 || newY < 0 || newX >= 4 || newY >= 4) {
continue;
}
//该节点的标记mark为1,已经访问过了,则不需要进队列了
if(mark[newX][newY] == 1) {
continue;
}
//已经找到相连节点,构建该节点,并入队列,标记为1
Node next = new Node(newX , newY , temp.dis+1);
//记录第1个节点到next节点的距离
map.put(arr[newX][newY], temp.dis+1);
mark[newX][newY] = 1;
queue.offer(next);
}//for
}//while
//输出节点到1节点的距离
for(Map.Entry<Integer, Integer> it:map.entrySet()) {
System.out.println("1->"+it.getKey()+":"+it.getValue());
}
}
}